<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>页面区块化与应用组件化 | 被删的前端游乐场</title>
    <meta name="description" content="Just playing around">
    
    
    <link rel="preload" href="/front-end-playground/assets/css/0.styles.a683ed26.css" as="style"><link rel="preload" href="/front-end-playground/assets/js/app.e5cf4092.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/3.c853767c.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/2.eed49fdd.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/38.2e692b7b.js" as="script">
    <link rel="stylesheet" href="/front-end-playground/assets/css/0.styles.a683ed26.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/front-end-playground/" class="home-link router-link-active"><!----> <span class="site-name">被删的前端游乐场</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link router-link-active">前端基础</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link router-link-active">前端基础</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前端入门</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-0cd75e06><span class="stand" data-v-0cd75e06></span> <div class="cat" data-v-0cd75e06><div class="body" data-v-0cd75e06></div> <div class="head" data-v-0cd75e06><div class="ear" data-v-0cd75e06></div> <div class="ear" data-v-0cd75e06></div></div> <div class="face" data-v-0cd75e06><div class="nose" data-v-0cd75e06></div> <div class="whisker-container" data-v-0cd75e06><div class="whisker" data-v-0cd75e06></div> <div class="whisker" data-v-0cd75e06></div></div> <div class="whisker-container" data-v-0cd75e06><div class="whisker" data-v-0cd75e06></div> <div class="whisker" data-v-0cd75e06></div></div></div> <div class="tail-container" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>前端深入理解</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/front-end-playground/front-end-basic/understanding/build-application.html" class="sidebar-link">前端构建大型应用</a></li><li><a href="/front-end-playground/front-end-basic/understanding/component-communication-with-data-model.html" class="sidebar-link">数据抽离与数据管理</a></li><li><a href="/front-end-playground/front-end-basic/understanding/component-with-configuration.html" class="sidebar-link">组件配置化</a></li><li><a href="/front-end-playground/front-end-basic/understanding/component-with-itself.html" class="sidebar-link">一个组件的自我修养</a></li><li><a href="/front-end-playground/front-end-basic/understanding/app-component-isolation.html" class="active sidebar-link">页面区块化与应用组件化</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/app-component-isolation.html#什么是区块" class="sidebar-link">什么是区块</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/app-component-isolation.html#什么是组件" class="sidebar-link">什么是组件</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/app-component-isolation.html#组件的划分" class="sidebar-link">组件的划分</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/app-component-isolation.html#组件的封装" class="sidebar-link">组件的封装</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/app-component-isolation.html#组件的通信" class="sidebar-link">组件的通信</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/understanding/app-component-isolation.html#组件化程度" class="sidebar-link">组件化程度</a></li></ul></li><li><a href="/front-end-playground/front-end-basic/understanding/template-engine.html" class="sidebar-link">前端模板引擎</a></li><li><a href="/front-end-playground/front-end-basic/understanding/dialogue-abstraction.html" class="sidebar-link">对话抽象</a></li><li><a href="/front-end-playground/front-end-basic/understanding/data-driven-or-event-driven.html" class="sidebar-link">前端思维转变--从事件驱动到数据驱动</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><p>很多时候，我们喜欢划分所谓技术需求和业务需求。但其实，技术来自于业务，业务需要技术支撑，两者是分不开的。我们可以尝试在业务里，一样地写出花来。</p> <h1 id="页面区块化"><a href="#页面区块化" aria-hidden="true" class="header-anchor">#</a> 页面区块化</h1> <p>其实页面区块化只是一种瞎说的术语，个人想说的是，将一个页面清晰地按照功能、业务、emmmmmmm。。。可能就是按照功能划分吧。这其实不完全属于前端的范畴，是贯穿业务、产品、设计、前端、甚至后台、终端的一整个团队的设计吧。</p> <h2 id="什么是区块"><a href="#什么是区块" aria-hidden="true" class="header-anchor">#</a> 什么是区块</h2> <p>我们来看看常用的应用吧，首先是知乎：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524064559%281%29.jpg" alt="image"></p> <p>简单划分下：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524064840%281%29.jpg" alt="image"></p> <p>大致我们可以分为三大块：</p> <ul><li>头部：快速导航栏</li> <li>左侧：内容板块</li> <li>右侧：推广板块</li></ul> <p>其实论坛类、博客类的页面大多如此，看看微博：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524065227%281%29.jpg" alt="image"></p> <p>除此之外，还有视频类、电商类等各种角色的网站，大家有空也可以去看看，思考下里面是怎么划分的。</p> <p>或许你会觉得，想这些有什么用呢？这对我的工作有什么帮助吗？嘛，个人觉得<code>观察 -&gt; 思考 -&gt; 总结</code>也是有意思的事情，可以多一种角度来思考自己的工作，也能提高工作的趣味性吧。</p> <p>如果你非要问，到底有什么用嘛~酱紫，容我细细道来吧。</p> <h1 id="应用组件化"><a href="#应用组件化" aria-hidden="true" class="header-anchor">#</a> 应用组件化</h1> <p>说到组件，这下总该不陌生吧，翻译下就是 component，这每个框架里面不都一抓一大把嘛。</p> <h2 id="什么是组件"><a href="#什么是组件" aria-hidden="true" class="header-anchor">#</a> 什么是组件</h2> <p>简答来说，<strong>组件可以扩展 HTML 元素，封装可重用的代码</strong>。</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!--长这样--&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>my-component</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>my-component</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>你说，啊？？？这什么都没有啊。停停停，这只是我们最后使用的样子，逻辑嘛，都封装在里面啦。</p> <p>一个组件，它的呈现可能会千奇百怪，因为不管怎么说，组件虽然可视为个体或是实例，但也是一种抽象。</p> <h2 id="组件的划分"><a href="#组件的划分" aria-hidden="true" class="header-anchor">#</a> 组件的划分</h2> <p>目前来说，通常的组件划分可从两个角度来进行：</p> <p><strong>1. 视觉和交互上是一个完整的组件。</strong>
这里挑了个视频网站，如图：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524109540%281%29.jpg" alt="image"></p> <p>通常我们第一眼看上去可区分出独立的视图和功能的，则可以列为这种组件的划分。或许也可以成为区块，是为视觉和交互上完整的组件。</p> <p><strong>2. 写代码的时候，可重复的内容即可视为一个组件。</strong></p> <p>还是这个网站，我们看：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524108519%281%29.jpg" alt="image"></p> <p>这里，我们能看到这种卡片形式的内容，存在页面中的各个地方。</p> <p>通常这种情况下，我们将其封装成一个简单的组件，包括图片+文字描述，当然还有一些简单的内容，可通过配置的方式来调整。</p> <p>这样，我们就能在很多地方，都能使用这个组件。这种方式的组件划分，在理解上或许没有从业务上划分的直观，但从另一种角度看，哪种方式效率高一些也不一定呢。</p> <p><strong>Tips.</strong>
在一个团队内，最好是使用一种方式来进行划分。因为对于成员的相互配合和项目的维护来说，统一的规范是比较重要的。</p> <h2 id="组件的封装"><a href="#组件的封装" aria-hidden="true" class="header-anchor">#</a> 组件的封装</h2> <p>个人认为，一个称职的组件，是以下形式的：</p> <ul><li><strong>组件内维护自身的数据和状态</strong></li> <li><strong>组件内维护自身的事件</strong></li> <li><strong>通过初始化事件（event、绑定的 scope 事件，传入数据），来初始化组件状态，激活组件</strong></li> <li><strong>对外提供配置项，来控制展示以及具体功能</strong></li> <li><strong>通过对外提供查询接口，可获取组件状态</strong></li></ul> <p>笼统地概括下，就是我们尽量需要把组件进行隔离，拥有独立的个体空间，同时保持与外界适当的联系。</p> <h3 id="组件内维护自身的数据和状态"><a href="#组件内维护自身的数据和状态" aria-hidden="true" class="header-anchor">#</a> 组件内维护自身的数据和状态</h3> <p>这个比较好理解，以上面的小卡片为例子：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524111302%281%29.jpg" alt=""></p> <p>这个小卡片，它维护着自己的数据：封面图、描述、头像、作者。还有一个初始的状态，就是目前我们看到的样子。
这些内容保存在组件自己的 scope 里，每个卡片组件都拥有自己的数据和状态。</p> <h3 id="组件内维护自身的事件"><a href="#组件内维护自身的事件" aria-hidden="true" class="header-anchor">#</a> 组件内维护自身的事件</h3> <p>我们在把鼠标放在卡片上，随着鼠标的位置，顶部会有个小小的进度条，同时封面图会改变，如图：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524111149%281%29.png" alt="image"></p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524111141%281%29.jpg" alt="image"></p> <p>每个小卡片都有自己 mousemove 事件。当然，这里面维护了一个鼠标位置的状态，同时根据鼠标位置来控制图片的展示。</p> <h3 id="通过初始化事件，来初始化组件状态，激活组件"><a href="#通过初始化事件，来初始化组件状态，激活组件" aria-hidden="true" class="header-anchor">#</a> 通过初始化事件，来初始化组件状态，激活组件</h3> <p>组件的数据，大多数需要外界提供并传入，故可通过初始化事件来激活。</p> <h3 id="对外提供配置项，来控制展示以及具体功能"><a href="#对外提供配置项，来控制展示以及具体功能" aria-hidden="true" class="header-anchor">#</a> 对外提供配置项，来控制展示以及具体功能</h3> <p>可以通过配置的方式，来控制组件的展示和功能。</p> <p>我们看这个小卡片：
<img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1524115436%281%29.jpg" alt="image"></p> <p>和上面的不一样，左下角展示的是视频时长，而不是头像和名字，这种我们可以通过配置的方式来控制。</p> <h3 id="通过对外提供查询接口，可获取组件状态"><a href="#通过对外提供查询接口，可获取组件状态" aria-hidden="true" class="header-anchor">#</a> 通过对外提供查询接口，可获取组件状态</h3> <p>很多时候，组件独立维护着自身的数据和状态，但有些场景下，父组件或者应用需要知道组件当前的状态，故我们需要对外提供接口，以供查询。</p> <p>像 Vue 中，便可以通过<code>vm.$refs</code>来获取子组件的实例。</p> <h2 id="组件的通信"><a href="#组件的通信" aria-hidden="true" class="header-anchor">#</a> 组件的通信</h2> <p>当我们层层封装组件后，或许就会带来组件间通信的问题。从最简单的父子组件、到同胞组件、到几乎毫无关系的组件的通信，我们可以有不同的解决方法。</p> <p><strong>1. 事件监听。</strong></p> <p>简单的，我们可以直接通过事件监听来通信，全局或是局部的监听和触发。</p> <p>但是使用频繁之后，我们会发现不好维护。为什么呢？因为你在追踪事件的触发和监听时，只能通过全局搜索对应的事件名称，这样数据流会有种到处乱窜、无法管理的感觉。</p> <p><strong>2. 对象数据。</strong></p> <p>我们也可以通过共享同一个对象的方式来管理。通过注入对象的引用，来在不同组件中获取相同的数据源。</p> <p>这样有时候还会存在问题，当我们需要获取新的数据实例时，则需要手动去维护。当然，在 Angular 里，则是通过提供通用的依赖注入方式，配合树状的模块管理，可通过局部注入实例来获取共享或是隔离的数据。</p> <p><strong>3. 状态流管理。</strong></p> <p>这是通过流的方式管理状态，常见的状态管理工具 Vuex、Redux 等，都是这样的方式去管理。</p> <p>即使是使用这样的流管理，也是通过对象数据的方式来管理。当然，加入了单向流动的方式，这样提高了维护性，因为你知道所有数据都从哪里流入、从哪里流出。</p> <h2 id="组件化程度"><a href="#组件化程度" aria-hidden="true" class="header-anchor">#</a> 组件化程度</h2> <p><strong>组件的封装是会消耗维护性的，过度的封装会导致代码难维护，可读性也差。</strong></p> <p>所以我们需要根据项目的大小以及复杂度，来进行什么程度的封装，当然封装除去组件的封装，还可以是数据、样式、功能的封装。</p> <p>尽管前端的框架或是能力一直在变化，但项目的维护始终是很重要的事情。不能因为说今天这套明天就不适用了，就不打算细细去做，我们要把思考和反省，贯穿在整个写码的人生中。</p> <p>适度也是很重要的，个人认为好的架构是变化的，跟随着项目变化而变化，保持着拓展性和维护性。如果说我们只是为了抽象而抽象，那想必会把简单的事情复杂化，整个应用和代码会变得难以理解。适度的抽象很重要，但相比错误的抽象过程，没有抽象可能会更好。</p> <h1 id="结束语"><a href="#结束语" aria-hidden="true" class="header-anchor">#</a> 结束语</h1> <p>回到文章开头，技术与业务是相关的，很多时候并不能简单地区分所谓技术需求和业务需求。同样的，业务需求也能写得很有意思，多多在里面掺杂些自己的想法吧，实践出真理~~<br>
关于组件封装的，后面会有其他文章详细说明哒，这里介绍下目前的主要想法而已。</p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/front-end-playground/edit/sourcecode/docs/front-end-basic/understanding/app-component-isolation.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></div> <!----> <blockquote>部分文章中使用了一些网站的截图，如果涉及侵权，请告诉我删一下谢谢~</blockquote> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本文版权归作者所有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。</div> <div>出处：被删的前端游乐场</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/front-end-playground/front-end-basic/understanding/component-with-itself.html" class="prev">
          一个组件的自我修养
        </a></span> <span class="next"><a href="/front-end-playground/front-end-basic/understanding/template-engine.html">
          前端模板引擎
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-1883" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty2.svg);"></div></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/front-end-playground/assets/js/app.e5cf4092.js" defer></script><script src="/front-end-playground/assets/js/3.c853767c.js" defer></script><script src="/front-end-playground/assets/js/2.eed49fdd.js" defer></script><script src="/front-end-playground/assets/js/38.2e692b7b.js" defer></script>
  </body>
</html>
